package cn.com.hhrcw.es.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务类
 * </p>
 *
 * @author lixingxing
 * @since 2020-08-12
 */
public interface IElasticsearchService {

	/**
	 * 添加
	 *
	 * @param documents
	 * @param <T>
	 */
	<T> void add(T... documents);

	/**
	 * 搜索
	 *
	 * @param searchRequest
	 * @param clz
	 * @param <T>
	 * @return
	 */
	<T> List<T> search(SearchRequest searchRequest, Class<T> clz);

	/**
	 * 分页搜索
	 *
	 * @param searchRequest
	 * @param page
	 * @param clz
	 * @param <T>
	 * @return
	 */
	<T> IPage<T> searchForPage(SearchRequest searchRequest, IPage<T> page, Class<T> clz);

	/**
	 * 删除
	 *
	 * @param clz
	 * @param id
	 * @param <T>
	 */
	<T> void delete(Class<T> clz, String... id);

	/**
	 * 构建搜索参数
	 *
	 * @param map
	 * @return
	 */
	default SearchRequest build(Map<String, String[]> map) {
		SearchSourceBuilder builder = new SearchSourceBuilder();
		BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
		Set<String> keySet = map.keySet();
		// 分词匹配
		List<String> keys = keySet.stream().filter(e -> e.endsWith(".keywords")).collect(Collectors.toList());
		for (String key : keys) {
			String value = map.get(key)[0];
			String[] split = key.split(",");
			if (split.length > 1) {
				for (int i = 0; i < split.length; i++) {
					split[i] = split[i].replace(".keywords", "");
				}
				boolQueryBuilder.must(QueryBuilders.multiMatchQuery(value, split));
			} else {
				boolQueryBuilder.must(QueryBuilders.matchQuery(key.replace(".keywords", ""), value));
			}
		}

		// 模糊匹配
		keys = keySet.stream().filter(e -> e.endsWith(".like")).collect(Collectors.toList());
		for (String key : keys) {
			boolQueryBuilder.must(QueryBuilders.wildcardQuery(key.replace(".like", ""), map.get(key)[0]));
		}

		// 精确匹配
		keys = keySet.stream().filter(e -> e.endsWith(".term")).collect(Collectors.toList());
		for (String key : keys) {
			String value = map.get(key)[0];
			boolQueryBuilder.must(QueryBuilders
					.termQuery(key.replace(".term", NumberUtil.isNumber(value) ? "" : ".keyword"), map.get(key)[0]));
		}

		// in 匹配
		keys = keySet.stream().filter(e -> e.endsWith(".in")).collect(Collectors.toList());
		if(!keys.isEmpty()){
			BoolQueryBuilder inQueryBuilder = QueryBuilders.boolQuery();
			for (String key : keys) {
				String value = map.get(key)[0];
				if(StrUtil.isNotBlank(value)){
					inQueryBuilder.should(QueryBuilders.termsQuery(key.replace(".in", NumberUtil.isNumber(value) ? "" : ".keyword"), Arrays.asList(value.split(","))));
				}
			}
			boolQueryBuilder.must(inQueryBuilder);
		}

		// <=
		keys = keySet.stream().filter(e -> e.endsWith(".lte")).collect(Collectors.toList());
		for (String key : keys) {
			RangeQueryBuilder minBuilder = QueryBuilders.rangeQuery(key.replace(".lte", "")).lte(map.get(key)[0]);
			boolQueryBuilder.must(minBuilder);
		}
		// >=
		keys = keySet.stream().filter(e -> e.endsWith(".gte")).collect(Collectors.toList());
		for (String key : keys) {
			RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(key.replace(".gte", ""))
					.gte(map.get(key)[0]);
			boolQueryBuilder.must(rangeQueryBuilder);
		}

		// 范围查询
		keys = keySet.stream().filter(e -> e.endsWith(".range")).collect(Collectors.toList());
		for (String key : keys) {
			String[] value = map.get(key)[0].split(",");
			RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(key.replace(".range", "")).lte(value[1])
					.gte(value[0]);
			boolQueryBuilder.must(rangeQueryBuilder);
		}
		builder.query(boolQueryBuilder);
		String[] fields = map.get("field");
		if (ArrayUtil.isNotEmpty(fields)) {
			String field = StrUtil.equals(map.get("field")[0], "money") ? "maxMoney" : map.get("field")[0];
			SortOrder sortOrder = Convert.toBool(map.get("sort")[0], true).booleanValue() ? SortOrder.ASC
					: SortOrder.DESC;
			builder.sort(field, sortOrder);
		}
		return new SearchRequest().source(builder);
	}
}
